package part14;

import java.util.*;

/**
 * @author wcj
 * @Date 2021/5/26 14:53
 * @Version 1.0
 */
public class Part147 {

    static class PetCounter extends HashMap<String, Integer> {
        public void count(String type) {
            Integer quantity = get(type);
            if (quantity == null) {
                put(type, 1);
            } else {
                put(type, quantity + 1);
            }
        }
    }

    /**
     * RTTI的三种形式：
     * 第一：传统的RTTI，即基类多导出类，通过多态的思想，将导出类向上转型为基类，从而调用通用方法
     * 第二种：利用Class对象获取类的运行时信息
     * 第三种：在运行时，通过instanceof关键字判断对象类型
     * 需要注意instanceof不应该被广泛使用
     * 另外：最好使用类字面量形式获取class对象
     *
     * @param creator
     */
    public static void countPets(PetCreator creator) {
        PetCounter petCounter = new PetCounter();
        for (Pet pet : creator.createArray(20)) {
            System.out.println(pet.getClass().getSimpleName() + "");
            if (pet instanceof Pet) {
                petCounter.count("Pet");
            }
            if (pet instanceof Dog) {
                petCounter.count("Dog");
            }
            if (pet instanceof Mutt) {
                petCounter.count("Mutt");
            }
            if (pet instanceof Pug) {
                petCounter.count("Pug");
            }
            if (pet instanceof Cat) {
                petCounter.count("Cat");
            }
            if (pet instanceof Manx) {
                petCounter.count("Manx");
            }
            if (pet instanceof Cymric) {
                petCounter.count("Cymric");
            }
            if (pet instanceof Rodent) {
                petCounter.count("Rodent");
            }
            if (pet instanceof Rat) {
                petCounter.count("Rat");
            }
            if (pet instanceof Mouse) {
                petCounter.count("Mouse");
            }
            if (pet instanceof Hamster) {
                petCounter.count("Hamster");
            }
        }
        System.out.println(petCounter);
    }

    public static void main(String[] args) {
        countPets(new ForNameCreator());
    }
}

class ForNameCreator extends PetCreator {

    private static List<Class<? extends Pet>> types = new ArrayList<>();
    private static String[] typeNames = {
            "part14.Mutt",
            "part14.Pug",
            "part14.EgyptianMau",
            "part14.Manx",
            "part14.Cymric",
            "part14.Rat",
            "part14.Mouse",
            "part14.Hamster"
    };

    private static void loader() {
        try {
            for (String type : typeNames) {
                types.add((Class<? extends Pet>) Class.forName(type));
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    static {
        loader();
    }

    @Override
    public List<Class<? extends Pet>> types() {
        return types;
    }
}

abstract class PetCreator {
    private Random random = new Random(47);

    public abstract List<Class<? extends Pet>> types();

    public Pet randomPet() {
        int i = random.nextInt(types().size());
        try {
            return types().get(i).newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public Pet[] createArray(int size) {
        Pet[] pets = new Pet[size];
        for (int i = 0; i < size; i++) {
            pets[i] = randomPet();
        }
        return pets;
    }

    public ArrayList<Pet> arrayList(int size) {
        ArrayList<Pet> pets = new ArrayList<>();
        Collections.addAll(pets, createArray(size));
        return pets;
    }
}

class Pet {
    public Pet(String name) {
        System.out.println(name);
    }

    public Pet() {
    }
}

class Dog extends Pet {
    public Dog(String name) {
        super(name);
    }

    public Dog() {
        super();
    }
}

class Mutt extends Dog {
    public Mutt(String name) {
        super(name);
    }

    public Mutt() {
    }
}

class Pug extends Dog {
    public Pug(String name) {
        super(name);
    }

    public Pug() {
    }
}

class Cat extends Pet {
    public Cat(String name) {
        super(name);
    }

    public Cat() {
    }
}

class EgyptianMau extends Cat {
    public EgyptianMau(String name) {
        super(name);
    }

    public EgyptianMau() {
    }
}

class Manx extends Cat {
    public Manx(String name) {
        super(name);
    }

    public Manx() {
    }
}

class Cymric extends Manx {
    public Cymric(String name) {
        super(name);
    }

    public Cymric() {
    }
}

class Rodent extends Pet {
    public Rodent(String name) {
        super(name);
    }

    public Rodent() {
    }
}

class Rat extends Rodent {
    public Rat(String name) {
        super(name);
    }

    public Rat() {
    }
}

class Mouse extends Rodent {
    public Mouse(String name) {
        super(name);
    }

    public Mouse() {
    }
}

class Hamster extends Rodent {
    public Hamster(String name) {
        super(name);
    }

    public Hamster() {
    }
}
